package com.itheima.stock.service.impl;

import com.alibaba.excel.EasyExcel;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.stock.constant.ChangeDate;
import com.itheima.stock.mapper.*;
import com.itheima.stock.pojo.domain.*;
import com.itheima.stock.pojo.vo.StockInfoConfig;
import com.itheima.stock.pojo.vo.req.PageResult;
import com.itheima.stock.pojo.vo.resp.R;
import com.itheima.stock.pojo.vo.resp.ResponseCode;
import com.itheima.stock.service.StockService;
import com.itheima.stock.utils.DateTimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;


import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StockServiceImpl implements StockService {

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;
    @Autowired
    private StockInfoConfig stockInfoConfig;
    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;
    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;
    @Autowired
    private Cache<String,Object> caffeineCache;
    @Autowired
    private StockBusinessMapper stockBusinessMapper;
    @Autowired
    private StockOuterMarketIndexInfoMapper stockOuterMarketIndexInfoMapper;

    @Override
    public R<List<InnerMarketDomain>> innerIndexAll() {

        Date timePoint = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();

//        timePoint = DateTime.parse("2021-12-28 09:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        List<String> marketIds = stockInfoConfig.getInner();
        List<InnerMarketDomain> data = stockMarketIndexInfoMapper.innerIndexAll(marketIds, timePoint);
        return R.ok(data);
    }

    @Override
    public R<List<BlockRtDomain>> BlockRtAll() {


        Date timePoint = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();

//        timePoint = DateTime.parse("2021-12-21 09:30:01", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        List<BlockRtDomain> data = stockBlockRtInfoMapper.BlockRtAll(timePoint);

        return R.ok(data);
    }

    @Override
    public R<List<OuterMarketDomain>> outerIndexAll() {
        Date timePoint = DateTime.now().minusMinutes(1).withSecondOfMinute(0).withMillisOfSecond(0).toDate();

//        timePoint = DateTime.parse("2021-12-01 10:57:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        List<String> marketIds = stockInfoConfig.getOuter();
        List<OuterMarketDomain> data = stockOuterMarketIndexInfoMapper.outerIndexAll(marketIds, timePoint);
        return R.ok(data);
    }

    @Override
    public R<PageResult<RtDomain>> RtPage(String page, String pageSize) {

        PageHelper.startPage(Integer.parseInt(page), Integer.parseInt(pageSize));

/*
        Date timePoint = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();

        timePoint = DateTime.parse("2022-05-18 15:58:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
*/


        List<RtDomain> rt = stockRtInfoMapper.RtPage();
        if (CollectionUtils.isEmpty(rt)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA);
        }
        PageResult<RtDomain> pageResult = new PageResult<>(new PageInfo<>(rt));
        return R.ok(pageResult);
    }

    @Override
    public R<List<RtDomain>> RtAll() {
/*
        Date timePoint = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();

        timePoint = DateTime.parse("2022-05-18 15:58:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
*/

        List<RtDomain> rt = stockRtInfoMapper.RtAll();

        return R.ok(rt);
    }

    @Override
    public R<Map<String, List>> UpDownCount() {

        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
//        curTime = DateTime.parse("2022-01-05 15:00:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        DateTime openDate = DateTimeUtil.getLastDate4Stock(DateTime.now());
//        openDate = DateTime.parse("2022-01-05 15:00:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date openTime = DateTimeUtil.getOpenDate(openDate).toDate();


        ArrayList<Map> upCount = stockRtInfoMapper.UpDownCount(openTime, curTime, 1);
        ArrayList<Map> downCount = stockRtInfoMapper.UpDownCount(openTime, curTime, 0);

        HashMap<String, List> map = new HashMap<>();

        new ArrayList<>();
        map.put("upList", upCount);
        map.put("downList", downCount);

        return R.ok(map);
    }

    @Override
    public void exportRtInfo(String page, String pageSize, HttpServletResponse response) {
        R<PageResult<RtDomain>> r = RtPage(page, pageSize);
        List<RtDomain> rows = r.getData().getRows();

        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        try {
            String fileName = URLEncoder.encode("股票信息表", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), RtDomain.class).sheet("股票信息").doWrite(rows);
        } catch (IOException e) {
            e.printStackTrace();
            log.info("当前导出数据异常，当前页：{},每页大小：{},异常信息：{}", page, pageSize, e.getMessage());
        }
    }

    @Override
    public R<Map<String, List>> stockTradeVol4InnerMarket() {

        DateTime curTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
//        Date curTime4T = DateTime.parse("2021-12-29 14:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        Date curTime4T = curTime.toDate();

        DateTime preCurTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).minusDays(1);
//        Date preCurTime4T = DateTime.parse("2021-12-28 14:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        Date preCurTime4T = preCurTime.toDate();
        Date openTime = DateTimeUtil.getOpenDate(curTime).toDate();
//        openTime = DateTime.parse("2021-12-29 09:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        Date preOpenTime = DateTimeUtil.getOpenDate(preCurTime).toDate();
//        preOpenTime = DateTime.parse("2021-12-28 09:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        List<String> inner = stockInfoConfig.getInner();

        List<Map<String, Long>> amtList = stockMarketIndexInfoMapper.stockTradeVol4InnerMarket(openTime, curTime4T, inner);
        List<Map<String, Long>> yesAmtList = stockMarketIndexInfoMapper.stockTradeVol4InnerMarket(preOpenTime, preCurTime4T, inner);

        HashMap<String, List> map = new HashMap<>();
        map.put("amtList", amtList);
        map.put("yesAmtList", yesAmtList);

        return R.ok(map);
    }

    @Override
    public R<Map> getStockUpDown() {
        Date pointTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        HashMap<Object, Object> map = new HashMap<>();

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        String curTime = format.format(pointTime);

        map.put("time", curTime);


        List<Map<String, Object>> infos = stockRtInfoMapper.getStockUpDown(pointTime);
//        List<Map> afterInfos = new ArrayList<>();
        List<String> rate = stockInfoConfig.getRate();

        List<Map> afterInfos = rate.stream().map(
                title -> {
                    Map map1 = null;
                    //rate中的title是否能在Infos中找到,如果有则返回这个info,如果没有,则返回null,一个一个找而不是一次性找一个集合
                        Optional<Map<String, Object>> op = infos.stream().filter(i -> i.containsValue(title)).findFirst();//1
                        if (op.isPresent()){
                            //获得op中存储的对象->1所返回的对象
                            map1 = op.get();
                        }
                        else
                        {
                            map1 = new HashMap();
                            map1.put("count", 0L);
                            map1.put("title", title);
                        }
                    return map1;
                }
        ).collect(Collectors.toList());

        map.put("infos",afterInfos);
/*
        for (String title : rate) {
            Map map1 = null;
            for (Map<String, Object> info : infos) {
                if (info.containsValue(title)) {
                    map1 = info;
                    break;
                }
            }
            if(map1==null) {
                map1 = new HashMap();
                map1.put("count", 0L);
                map1.put("title", title);
            }
            afterInfos.add(map1);
        map.put("infos",afterInfos);*/
        System.out.println(map);
        return R.ok(map);
    }

    @Override
    public R<List<Stock4MinuteDomain>> stockScreenTimeSharing(String code) {

        DateTime pointTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
//        Date curTime  = DateTime.parse("2021-12-30 14:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        Date curTime  = pointTime.toDate();
        DateTime openTime = DateTimeUtil.getOpenDate(pointTime);
//        Date startTime  = DateTime.parse("2021-12-30 9:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        Date startTime  = openTime.toDate();
        List<Stock4MinuteDomain> minuteDomains = stockRtInfoMapper.stockScreenTimeSharing(startTime,curTime,code);

        return R.ok(minuteDomains);
    }

    @Override
    public R<List<Stock4EvrDayDomain>> getDayKLinData(String code) {
/*        DateTime now = DateTimeUtil.getLastDate4Stock(DateTime.now().minusYears(2));
        Date closeTime = now.toDate();
        Date openTime = now.minusYears(ChangeDate.MINUSYEARS).toDate();
        List<Stock4EvrDayDomain> evrDayDomains = stockRtInfoMapper.getDayKLinData(openTime,closeTime,code);*/
        DateTime now = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date closeTime = now.toDate();
        Date openTime = now.minusWeeks(ChangeDate.MINUSWEEKS).toDate();
        List<LocalDateTime> maxCurTimes = stockRtInfoMapper.getDayMaxCurTime(openTime,closeTime,code);
        List<Date> mxTimes = new ArrayList<>();
        for (LocalDateTime maxCurTime : maxCurTimes) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String mxDate = formatter.format(maxCurTime);
            Date mxTime = DateTime.parse(mxDate,DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
            mxTimes.add(mxTime);
        }
        List<Stock4EvrDayDomain> evrDayDomains = stockRtInfoMapper.getDayKLinDataByTime(mxTimes,code);

        return R.ok(evrDayDomains);
    }

    @Override
    public R<List<InnerMarketDomain>>  getNewestInnerMarketInfos() {
        R<List<InnerMarketDomain>> result = (R<List<InnerMarketDomain>>) caffeineCache.get("innerMarketInfosKey", key -> {
            Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
//            lastDate = DateTime.parse("2022-01-03 09:47:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
            //2.获取国内大盘编码集合
            List<String> innerCodes = stockInfoConfig.getInner();
            //3.调用mapper查询
            List<InnerMarketDomain> innerInfos = stockMarketIndexInfoMapper.innerIndexAll(innerCodes, lastDate);
            return R.ok(innerInfos);
        });
        //4.响应
        return result;
    }

    @Override
    public R<List<RtDomain>> getNewestStockRtInfos() {

        R<List<RtDomain>> result = (R<List<RtDomain>>)caffeineCache.get("stockRtInfosKey", key -> {
            List<RtDomain> domains = stockRtInfoMapper.RtAll();
            return R.ok(domains);
        });
        return result;
    }

    @Override
    public R<List<BlockRtDomain>> getNewestBlockRtInfos() {

        R<List<BlockRtDomain>> result = (R<List<BlockRtDomain>>) caffeineCache.get("blockRtInfosKey", key -> {
            Date date = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
//            date = DateTime.parse("2022-01-03 09:47:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
            List<BlockRtDomain> blockRtDomains = stockBlockRtInfoMapper.BlockRtAll(date);
            return R.ok(blockRtDomains);
        });
        return result;
    }

    @Override
    public R<List<OuterMarketDomain>> getNewestOuterMarketInfos() {
        R<List<OuterMarketDomain>> result = (R<List<OuterMarketDomain>>)caffeineCache.get("outerMarketInfosKey", key -> {
            Date date = DateTime.now().minusMinutes(1).withSecondOfMinute(0).withMillisOfSecond(0).toDate();
            List<String> stockCode = stockInfoConfig.getOuter();
            List<OuterMarketDomain> domains = stockOuterMarketIndexInfoMapper.outerIndexAll(stockCode, date);
            return R.ok(domains);
        });
        return result;
    }

    @Override
    public R<List<Map>> searchStock(String searchStr) {

        System.out.println(searchStr);
        List<Map> stocks= stockBusinessMapper.searchStock(searchStr);
        return R.ok(stocks);
    }

    @Override
    public R<DescribeDomain> getDescribe(String code) {
        DescribeDomain describeDomain = stockBusinessMapper.getDescribe(code);
        System.out.println(describeDomain);
        return R.ok(describeDomain);
    }

    @Override
    public R<List<WeekklineDomain>> getWeekkline(String code) {



        /*DateTime now = DateTimeUtil.getLastDate4Stock(DateTime.now().minusYears(2));
        Date closeTime = now.toDate();
        Date openTime = now.minusYears(ChangeDate.MINUSYEARS).toDate();
        List<WeekklineDomain> weekkline = stockRtInfoMapper.getWeekkline(openTime,closeTime,code);
        return R.ok(weekkline);*/
/*        //截止时间
        Date endTime=DateTime.parse("2022-05-22 09:30:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //开始时间
        Date startTime=DateTime.parse("2021-01-01 09:30:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();*/
        DateTime now = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endTime = now.toDate();
        Date startTime = now.minusMonths(ChangeDate.MINUSMOUTH).toDate();
        //根据指定日期范围查询周K线数据
        List<WeekklineBeforeDomain> infos=stockRtInfoMapper.getWeekklineBefore(startTime,endTime,code);
        List<Date> mxTimes = new ArrayList<>();
        List<Date> miTimes = new ArrayList<>();
        List<WeekklineDomain> domains = new ArrayList<>();

        for (WeekklineBeforeDomain info : infos) {
            WeekklineDomain domain = new WeekklineDomain();
            domains.add(domain);
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

            String mxDate = formatter.format(info.getMiTime());
            String miDate = formatter.format(info.getMiTime());
            Date mxTime = DateTime.parse(mxDate,DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
            Date miTime = DateTime.parse(miDate,DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
            BeanUtils.copyProperties(info,domain);
            mxTimes.add(mxTime);
            miTimes.add(miTime);
        }
        List<BigDecimal> openPrices = stockRtInfoMapper.getOpenPrice(miTimes,code);
        List<BigDecimal> closePrices = stockRtInfoMapper.getClosePrice(mxTimes,code);


        for (int i = 0; i < domains.size(); i++) {
            domains.get(i).setOpenPrice(openPrices.get(i));
            domains.get(i).setClosePrice(closePrices.get(i));
        }
        return R.ok(domains);
    }

    @Override
    public R<DetailDomain> getRtDetail(String code) {

        Date pointTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
//        pointTime = DateTime.parse("2021-12-30 09:32:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        DetailDomain detailDomain = stockRtInfoMapper.getRtDetail(pointTime,code);
        return R.ok(detailDomain);
    }

    @Override
    public R<List<TradeDomain>> getRtTrade(String code) {
        DateTime startDate = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date startTime = DateTimeUtil.getOpenTime(startDate).toDate();
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
//        startTime = DateTime.parse("2021-12-30 09:32:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//        curTime = DateTime.parse("2021-12-30 10:56:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        List<TradeDomain> tradeDomain = stockRtInfoMapper.getRtTrade(startTime,curTime,code);
        return R.ok(tradeDomain);
    }
}
